package com.ttbj.util;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class ClassUtil {


    /**
     * 加载指定的类
     *
     * @param className
     * @return
     * @throws ClassNotFoundException
     */
    public Class loadClass(String className) throws ClassNotFoundException {
        Class theClass = null;
        try {
            theClass = Class.forName(className);
        } catch (ClassNotFoundException e1) {
            try {
                theClass = Thread.currentThread().getContextClassLoader().loadClass(className);
            } catch (ClassNotFoundException e2) {
                theClass = getClass().getClassLoader().loadClass(className);
            }
        }
        return theClass;
    }


    /**
     * 获取指定类的全部属性字段
     *
     * @param className
     * @return
     */
    public static String[] getField(String className) throws ClassNotFoundException {
        Class   classz = Class.forName(className);
        Field[] fields = classz.getFields();
        Field[] fieldz = classz.getDeclaredFields();

        Set<String> set = new HashSet<String>();
        for (Field f : fields) {
 
            set.add(f.getName());
        }
        for (Field f : fieldz) {
            set.add(f.getName());
        }
        return set.toArray(new String[]{});
    }

    /**
     * 获取对象的全部方法
     *
     * @param className
     * @return
     */
    public static String[] getMethod(String className) throws ClassNotFoundException {
        Class       classz  = Class.forName(className);
        Method[]    methods = classz.getMethods();
        Set<String> set     = new HashSet<String>();
        if (methods != null) {
            for (Method f : methods) {
                set.add(f.getName());
            }
        }
        return set.toArray(new String[]{});
    }


    /**
     * 同名属性值复制
     * 将对象obj内属性名同类型T内容有同名属性的值复制到类型T中，并返回一个类型T的对象
     *
     * @param obj
     * @param type
     * @param <T>
     * @return
     */
    public static <T> T propertiesCopy(Object obj, Class<T> type) {
        return null;
    }

    /**
     * 同名属性值复制（忽略大小写）
     * 将对象obj内属性名同类型T内容有同名属性的值复制到类型T中，并返回一个类型T的对象
     *
     * @param obj
     * @param type
     * @param <T>
     * @return
     */
    public static <T> T propertiesCopyIgnore(Object obj, Class<T> type) {
        return null;
    }

    /**
     * 同名属性值复制（比较时忽略字符IgnoreStr的内容）
     * 将对象obj内属性名同类型T内容有同名属性的值复制到类型T中，并返回一个类型T的对象
     *
     * @param obj
     * @param type
     * @param IgnoreStr
     * @param <T>
     * @return
     */
    public static <T> T propertiesCopyIgnoreFilter(Object obj, Class<T> type, String IgnoreStr) {
        return null;
    }

    /**
     * 调用对象的setter方法
     *
     * @param obj
     * @param att
     * @param value
     * @param type
     */
    public static void setter(Object obj, String att, Object value, Class<?> type) {
        try {
            Method met = obj.getClass().getMethod(
                    "set" + initStr(att),
                    type);
            met.invoke(
                    obj,
                    value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 调用对象的getter方法
     *
     * @param obj
     * @param att
     */
    public static void getter(Object obj, String att) {
        try {
            Method met = obj.getClass().getMethod("get" + initStr(att));
            System.out.println(met.invoke(obj));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String initStr(String old) {
        String str = old.substring(
                0,
                1).toUpperCase() + old.substring(1);
        return str;
    }


    public static List<String> getClassName(String packageName, boolean childPackage) {
        List<String> fileNames = null;
        ClassLoader  loader    = Thread.currentThread().getContextClassLoader();
        String packagePath = packageName.replace(
                ".",
                "/");
        URL url = loader.getResource(packagePath);
        if (url != null) {
            String type = url.getProtocol();
            if (type.equals("file")) {
                fileNames = getClassNameByFile(
                        url.getPath(),
                        null,
                        childPackage);
            } else if (type.equals("jar")) {
                fileNames = getClassNameByJar(
                        url.getPath(),
                        childPackage);
            }
        } else {
            fileNames = getClassNameByJars(
                    ((URLClassLoader) loader).getURLs(),
                    packagePath,
                    childPackage);
        }
        if (null != fileNames) {
            List<String> temp = new ArrayList<String>();
            for (String t : fileNames) {
                t = t.substring(
                        t.indexOf(packageName),
                        t.length());
                temp.add(t);
            }
            fileNames = temp;
        }
        return fileNames;
    }

    /**
     * 从项目文件获取某包下所有类
     *
     * @param filePath     文件路径
     * @param className    类名集合
     * @param childPackage 是否遍历子包
     * @return 类的完整名称
     */
    private static List<String> getClassNameByFile(String filePath, List<String> className, boolean childPackage) {
        List<String> myClassName = new ArrayList<String>();
        File         file        = new File(filePath);
        File[]       childFiles  = file.listFiles();
        for (File childFile : childFiles) {
            if (childFile.isDirectory()) {
                if (childPackage) {
                    myClassName.addAll(
                            getClassNameByFile(
                                    childFile.getPath(),
                                    myClassName,
                                    childPackage));
                }
            } else {
                String childFilePath = childFile.getPath();
                if (childFilePath.endsWith(".class")) {
                    childFilePath = childFilePath.substring(
                            childFilePath.indexOf("\\classes") + 9,
                            childFilePath.lastIndexOf("."));
                    childFilePath = childFilePath.replace(
                            "\\",
                            ".");
                    myClassName.add(childFilePath);
                }
            }
        }

        return myClassName;
    }

    /**
     * 从jar获取某包下所有类
     *
     * @param jarPath      jar文件路径
     * @param childPackage 是否遍历子包
     * @return 类的完整名称
     */
    private static List<String> getClassNameByJar(String jarPath, boolean childPackage) {
        List<String> myClassName = new ArrayList<String>();
        String[]     jarInfo     = jarPath.split("!");
        String       jarFilePath = jarInfo[0].substring(jarInfo[0].indexOf("/"));
        String       packagePath = jarInfo[1].substring(1);
        try {
            JarFile jarFile = new JarFile(jarFilePath);
            Enumeration<JarEntry> entrys = jarFile.entries();
            while (entrys.hasMoreElements()) {
                JarEntry jarEntry = entrys.nextElement();
                String entryName = jarEntry.getName();
                if (entryName.endsWith(".class")) {
                    if (childPackage) {
                        if (entryName.startsWith(packagePath)) {
                            entryName = entryName.replace(
                                    "/",
                                    ".").substring(
                                    0,
                                    entryName.lastIndexOf("."));
                            myClassName.add(entryName);
                        }
                    } else {
                        int index = entryName.lastIndexOf("/");
                        String myPackagePath;
                        if (index != -1) {
                            myPackagePath = entryName.substring(
                                    0,
                                    index);
                        } else {
                            myPackagePath = entryName;
                        }
                        if (myPackagePath.equals(packagePath)) {
                            entryName = entryName.replace(
                                    "/",
                                    ".").substring(
                                    0,
                                    entryName.lastIndexOf("."));
                            myClassName.add(entryName);
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return myClassName;
    }

    /**
     * 从所有jar中搜索该包，并获取该包下所有类
     *
     * @param urls         URL集合
     * @param packagePath  包路径
     * @param childPackage 是否遍历子包
     * @return 类的完整名称
     */
    private static List<String> getClassNameByJars(URL[] urls, String packagePath, boolean childPackage) {
        List<String> myClassName = new ArrayList<String>();
        if (urls != null) {
            for (int i = 0; i < urls.length; i++) {
                URL url = urls[i];
                String urlPath = url.getPath();
                // 不必搜索classes文件夹
                if (urlPath.endsWith("classes/")) {
                    continue;
                }
                String jarPath = urlPath + "!/" + packagePath;
                myClassName.addAll(
                        getClassNameByJar(
                                jarPath,
                                childPackage));
            }
        }
        return myClassName;
    }

    
    
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static ArrayList<Class> getAllClassByInterface(Class clazz,String packageName) {
        if(packageName.isEmpty()){
        	packageName = clazz.getPackage().getName();
        }
        ArrayList<Class> list = new ArrayList<>();
        // 判断是否是一个接口
        if (clazz.isInterface()) {
            try {
                ArrayList<Class> allClass = getAllClass(packageName);
                /**
                 * 循环判断路径下的所有类是否实现了指定的接口 并且排除接口类自己
                 */
                for (int i = 0; i < allClass.size(); i++) {
                    /**
                     * 判断是不是同一个接口
                     */
                    // isAssignableFrom:判定此 Class 对象所表示的类或接口与指定的 Class
                    // 参数所表示的类或接口是否相同，或是否是其超类或超接口
                    if (clazz.isAssignableFrom(allClass.get(i))) {
                        if (!clazz.equals(allClass.get(i))) {
                            // 自身并不加进去
                            list.add(allClass.get(i));
                        }
                    }
                }
            } catch (Exception e) {
                System.out.println("出现异常");
            }
        } else {
            // 如果不是接口，则获取它的所有子类
            try {
                ArrayList<Class> allClass = getAllClass(packageName);
                /**
                 * 循环判断路径下的所有类是否继承了指定类 并且排除父类自己
                 */
                for (int i = 0; i < allClass.size(); i++) {
                    if (clazz.isAssignableFrom(allClass.get(i))) {
                        if (!clazz.equals(allClass.get(i))) {
                            // 自身并不加进去
                            list.add(allClass.get(i));
                        }
                    }
                }
            } catch (Exception e) {
                System.out.println("出现异常");
            }
        }
        return list;
    }

    /**
     * 从一个指定路径下查找所有的类
     * 
     * @param name
     */
    @SuppressWarnings("rawtypes")
    private static ArrayList<Class> getAllClass(String packagename) {
        ArrayList<Class> list = new ArrayList<>();
        // 返回对当前正在执行的线程对象的引用。
        // 返回该线程的上下文 ClassLoader。
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        String path = packagename.replace('.', '/');
        try {
            ArrayList<File> fileList = new ArrayList<>();
            /**
             * 这里面的路径使用的是相对路径 如果大家在测试的时候获取不到，请理清目前工程所在的路径 使用相对路径更加稳定！
             * 另外，路径中切不可包含空格、特殊字符等！
             */
            // getResources:查找所有给定名称的资源
            // 获取jar包中的实现类:Enumeration<URL> enumeration =
            // classLoader.getResources(path);
            Enumeration<URL> enumeration = classLoader.getResources("../bin/" + path);
            while (enumeration.hasMoreElements()) {
                URL url = enumeration.nextElement();
                // 获取此 URL 的文件名
                fileList.add(new File(url.getFile()));
            }
            for (int i = 0; i < fileList.size(); i++) {
                list.addAll(findClass(fileList.get(i), packagename));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 如果file是文件夹，则递归调用findClass方法，或者文件夹下的类 如果file本身是类文件，则加入list中进行保存，并返回
     * 
     * @param file
     * @param packagename
     * @return
     */
    @SuppressWarnings("rawtypes")
    private static ArrayList<Class> findClass(File file, String packagename) {
        ArrayList<Class> list = new ArrayList<>();
        if (!file.exists()) {
            return list;
        }
        // 返回一个抽象路径名数组，这些路径名表示此抽象路径名表示的目录中的文件。
        File[] files = file.listFiles();
        for (File file2 : files) {
            if (file2.isDirectory()) {
                // assert !file2.getName().contains(".");// 添加断言用于判断
                if (!file2.getName().contains(".")) {
                    ArrayList<Class> arrayList = findClass(file2, packagename + "." + file2.getName());
                    list.addAll(arrayList);
                }
            } else if (file2.getName().endsWith(".class")) {
                try {
                    // 保存的类文件不需要后缀.class
                    list.add(Class.forName(packagename + '.' + file2.getName().substring(0, file2.getName().length() - 6)));
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
        return list;
    }
    
    
    public static void main(String[] args) throws ClassNotFoundException {
/*    	ArrayList<Class> allClassByInterface = getAllClassByInterface(java.lang.annotation.Annotation.class,"org.hibernate.validator.constraints");
    	System.out.println(allClassByInterface);
    	for (Class class1 : allClassByInterface) {
			System.out.println(class1.getName());
			
		}*/
 
    		 
    		 File f = new File(net.sf.cglib.beans.BeanCopier.class.getResource("/").getPath());
    		 System.out.println(f.toPath());
    		 
    		 String[] field = getField("com.ttbj.product.bean.dto.UserDto");
    		 System.out.println(field.length);
    }
    
    
}
